package com.mytx.search;

import com.mytx.common.annotation.SerializedField;
import com.mytx.common.exception.EncryptException;
import com.mytx.common.utils.HttpEncryptUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SuppressWarnings("Duplicates")
@Order(1)
@ControllerAdvice(basePackages = "com.mytx.search.controller")
public class MyResponseBodyAdvice implements ResponseBodyAdvice {
    private Logger logger = LoggerFactory.getLogger(MyResponseBodyAdvice.class);

    //排除项
    private String[] excludes = {};
    //是否加密,默认加密
    private boolean encode;


    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        //判断返回的对象是单个对象，还是list，还是map
        if (body == null) {
            return null;
        }
//        HttpHeaders headers = request.getHeaders();
//        if (headers.containsKey("AK")) {
//            List<String> ak = headers.getTopicById("AK");
//            logger.info("获取到aesKey2:" + JSONObject.toJSONString(ak));
//        }
        //重新初始化为默认值
        encode = true;
        excludes = new String[]{};

        if (returnType.getMethod().isAnnotationPresent(SerializedField.class)) {
            //获取注解配置的包含和去除字段
            SerializedField serializedField = returnType.getMethodAnnotation(SerializedField.class);
            excludes = serializedField.excludes();
            //是否加密
            encode = serializedField.encrypt();

        }
        //如果无须加密，那就在body增加field 标识一下，让客户端知道是否需要解密
        if (!encode) {
           // logger.info("返回数据不加密:" + request.getURI());
            //判断是否需要给响应的数据加上 是否加密的标识，0标识未加密，如果返回数据中没有标识，说明是加密的，因为默认是加密返回
            response.getHeaders().add("Encrypt", "0");//加上Encrypt的头信息，表示不加密
            return body;
        }

        String aesKsy = "";
        if (request instanceof ServletServerHttpRequest) {
            HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
            aesKsy = servletRequest.getHeader("AK");

        }
        //如果没有要排除的字段，直接加密返回
        if (excludes.length == 0) {
            if (encode) {
                return encode(aesKsy, body);
            }
            return body;
        }
        //去掉方法上注解中指定要排除的字段
        Object retObj;
        if (body instanceof List) {
            //List
            List list = (List) body;
            retObj = handleList(list);
        } else {
            //Single Object
            retObj = handleSingleObject(body);
        }
        //加密
        if (encode) {
            return encode(aesKsy, retObj);
        }
        return retObj;
    }

    private Object encode(String aesKey, Object content) {

        if (StringUtils.isEmpty(aesKey)) {
            logger.error("需要加密，但是没有AES秘钥,直接返回");
            throw new EncryptException("加密出错，没有AES秘钥");
        }

      //  logger.info("返回给app加密前的内容：" + JSONObject.toJSONString(content));
        Object encrypt;
        try {
            encrypt = HttpEncryptUtil.serverEncrypt(aesKey, content);
        } catch (Exception e) {
            e.printStackTrace();
            throw new EncryptException("加密出错" + e.getMessage());
        }
        return encrypt;
    }

    /**
     * 处理返回值是列表
     *
     * @param list
     * @return
     */
    private List handleList(List list) {
        List retList = new ArrayList();
        for (Object o : list) {
            Object map = handleSingleObject(o);
            retList.add(map);
        }
        return retList;
    }

    /**
     * 处理返回值是单个enity对象
     *
     * @param body
     * @return
     */
    private Object handleSingleObject(Object body) {
        Map<String, Object> map = new HashMap<>();

        Field[] fields = body.getClass().getDeclaredFields();
        for (Field field : fields) {

            //去除字段
            if (excludes.length > 0) {
                if (!isStringInArray(field.getName(), excludes)) {

                    try {
                        map.put(field.getName(), field.get(body));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        return map;
    }

    private boolean isStringInArray(String fieldName, String[] array) {
        for (String val : array) {
            if (fieldName.equals(val)) {
                return true;
            }
        }
        return false;
    }

}
